// Copyright 2022 Chen Jun
// Licensed under the MIT License.

#ifndef ARMOR_DETECTOR__DETECTOR_HPP_
#define ARMOR_DETECTOR__DETECTOR_HPP_

// OpenCV
#include <opencv2/core.hpp>
#include <opencv2/core/types.hpp>

// STD
#include <cmath>
#include <string>
#include <vector>

#include "Data/DataType.hpp"
#include "Data/armor.hpp"
#include "number_classifier.hpp"

namespace hnurm
{
    class Detector
    {
    public:
        struct LightParams
        {
            // width / height
            double min_ratio;
            double max_ratio;
            // vertical angle
            double max_angle;
        };

        struct ArmorParams
        {
            double min_light_ratio;
            double min_small_center_distance;
            double max_small_center_distance;
            double min_large_center_distance;
            double max_large_center_distance;
            // horizontal angle
            double max_angle;
        };

        struct CenterParams
        {
            double min_size;
            double max_size;
        };

        explicit Detector(const cv::FileNode& cfg_node);

        Detector(const int &init_min_l, const int &init_color, const LightParams &init_l,
                const ArmorParams &init_a);

        Detector() = default;

        int min_lightness{};
        LightParams l{};
        ArmorParams a{};
        CenterParams c{};

        std::unique_ptr<NumberClassifier> classifier;

        // Debug msgs
        cv::Mat binary_img;

        std::vector<Armor> detect(const cv::Mat &input, int self_color);

        Energybuff detect_buff(const cv::Mat &input,int self_color);

        void drawResults(cv::Mat &img);

        cv::Mat getAllNumbersImage();

        cv::Mat preprocessImage(const cv::Mat &input) const;

        std::vector<Light> findLights(const cv::Mat &rbg_img, const cv::Mat &_binary_img);

        std::vector<Armor> matchLights(const std::vector<Light> &lights, int self_color);

        std::vector<Center> findCenter(const cv::Mat &rbg_img, const cv::Mat &_binary_img);

        std::vector<Flabellum> findFlabellum(const cv::Mat &rbg_img, const cv::Mat &_binary_img);

        Energybuff energybuff_;

    private:
        std::vector<Light> lights_;
        std::vector<Armor> armors_;
        std::vector<Center> centers_;
        std::vector<Flabellum> flabellums_;
        cv::RotatedRect target_;

        bool isLight(const Light &light);

        static bool containLight(
                const Light &light_1, const Light &light_2, const std::vector<Light> &lights);

        bool isArmor(Armor &armor);
    };

}// namespace hnurm

#endif// ARMOR_DETECTOR__DETECTOR_HPP_
